package LeetDev.a3d;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

public class SubMesh {
	private Vect m_center;
	private Material m_material;
	private int m_numTriangles;
	private int m_numVertices;
	private int m_numSkinWidth;
	private ShortBuffer m_faces;
	private IntBuffer m_vertices;
	private IntBuffer m_normals;
	private IntBuffer m_texcoords;
	private byte m_type;
	private FloatBuffer m_weights;
	private ByteBuffer m_jointIndexes;
	
	public boolean haveAlpha()
	{
		return(m_material.haveAlpha());
	}
	public int getTriangleNum()
	{
		return(m_numTriangles);
	}
	public float calcDist(final Matrix matrix)
	{
		return((matrix.m[2]*m_center.x+matrix.m[6]*m_center.y+matrix.m[10]*m_center.z+matrix.m[14])-Camera.getCurrentCamera().getPosition().z);
	}

	public SubMesh(FileInput fin,final Material[] material_ref) throws Exception
	{
		m_faces=null;
		m_vertices=null;
		m_material=null;
		m_weights=null;
		m_jointIndexes=null;

		short mat;
		mat=fin.popShort();
		m_material=material_ref[mat];
		m_center=new Vect(fin.popFloat(),fin.popFloat(),fin.popFloat());
		m_numTriangles=fin.popInt();

		m_numVertices=fin.popInt();
		m_numSkinWidth=fin.popInt();
		m_type=fin.popByte();
        ByteBuffer fbb = ByteBuffer.allocateDirect(m_numTriangles*3*2);
        fbb.order(ByteOrder.nativeOrder());
        m_faces = fbb.asShortBuffer();
		switch(m_type)
		{
			case 0:
			{
				for(int i=0;i<m_numTriangles;++i)
				{
					m_faces.put(fin.popShort());
					m_faces.put(fin.popShort());
					m_faces.put(fin.popShort());
				}
				break;
			}
			case 1:
			{
				// Reserved for BSP transparency sorting.
				break;
			}
		}
        fbb.position(0);
        m_faces.position(0);
        
        ByteBuffer vbb,nbb,tbb;
		vbb=ByteBuffer.allocateDirect(m_numVertices*3*4);
        vbb.order(ByteOrder.nativeOrder());
		nbb=ByteBuffer.allocateDirect(m_numVertices*3*4);
        nbb.order(ByteOrder.nativeOrder());
        m_vertices = vbb.asIntBuffer();
        m_normals = nbb.asIntBuffer();
        
		if(m_material.isTextured())
		{
			tbb=ByteBuffer.allocateDirect(m_numVertices*2*4);
	        tbb.order(ByteOrder.nativeOrder());
	        m_texcoords = tbb.asIntBuffer();
	        
			for(int i=0;i<m_numVertices;++i)
			{
				m_texcoords.put(fin.popFixed());
				m_texcoords.put(fin.popFixed());
				m_normals.put(fin.popFixed());
				m_normals.put(fin.popFixed());
				m_normals.put(fin.popFixed());
				m_vertices.put(fin.popFixed());
				m_vertices.put(fin.popFixed());
				m_vertices.put(fin.popFixed());
			}
	        tbb.position(0);
	        m_texcoords.position(0);
		}
		else
		{
			for(int i=0;i<m_numVertices;++i)
			{
				m_normals.put(fin.popFixed());
				m_normals.put(fin.popFixed());
				m_normals.put(fin.popFixed());
				m_vertices.put(fin.popFixed());
				m_vertices.put(fin.popFixed());
				m_vertices.put(fin.popFixed());
			}
		}
        vbb.position(0);
        nbb.position(0);
        m_vertices.position(0);
        m_normals.position(0);
        
		if(m_numSkinWidth!=0)
		{
	        ByteBuffer wbb = ByteBuffer.allocateDirect(m_numVertices*m_numSkinWidth*4);
	        wbb.order(ByteOrder.nativeOrder());
	        m_weights = wbb.asFloatBuffer();
			for(int i=0;i<m_numVertices*m_numSkinWidth;++i)
			{
				m_weights.put(fin.popFloat());
			}
			m_weights.position(0);
			
			m_jointIndexes=ByteBuffer.allocateDirect(m_numVertices*m_numSkinWidth);
			for(int i=0;i<m_numVertices*m_numSkinWidth;++i)
			{
				m_jointIndexes.put(fin.popByte());
			}
			m_jointIndexes.position(0);
		}
		
		// Debug verification of arrays
        fbb.position(0);
		for(int i=0;i<m_numTriangles;++i)
		{
			short v=m_faces.get();
			if(v>=(short)m_numVertices)
			{
				throw new ArrayIndexOutOfBoundsException();
			}
			v=m_faces.get();
			if(v>=(short)m_numVertices)
			{
				throw new ArrayIndexOutOfBoundsException();
			}
			v=m_faces.get();
			if(v>=(short)m_numVertices)
			{
				throw new ArrayIndexOutOfBoundsException();
			}
		}
        fbb.position(0);
        m_faces.position(0);
	}
	
	public void draw(GL10 gl)
	{
		gl.glVertexPointer(3,GL10.GL_FIXED,0, m_vertices);
		gl.glNormalPointer(GL10.GL_FIXED,0, m_normals);
		
		m_material.use(gl);
		if(m_material.isTextured())
		{
			gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
			gl.glTexCoordPointer(2,GL10.GL_FIXED,0, m_texcoords);
		}
		else
		{
			gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		}
			
		if(m_type==1)
		{
			return;
		}
		gl.glDrawElements(GL10.GL_TRIANGLES,m_numTriangles*3,GL10.GL_UNSIGNED_SHORT,m_faces);
	}
	
}
